package com.currency.util;

import cn.hutool.http.HttpUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.currency.exception.AppException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.math.BigDecimal;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class WithdrawalUtil {
    // 支付宝相关
    private static final Log log = LogFactory.get(WithdrawalUtil.class);
    private static final String appId = "";
    private static final String privateKey = "";
    private static final String publicKey = "";


    // 微信相关
    public static final String wxAppId = "";
    public static final String wxAppSecret = "";
    public static final String mch_id = "";


    public static String wxToken = "";
    public static long tokenTime = 0L;
    public static Lock lock = new ReentrantLock();

    public WithdrawalUtil() throws KeyStoreException {
    }


    public static void newPayInit(String outNum, String appCertPath, String alipayCertPath, String alipayRootCertPath) throws Exception {
        //构造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        //设置网关地址
        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
        //设置应用Id
        certAlipayRequest.setAppId(appId);
        //设置应用私钥
        certAlipayRequest.setPrivateKey(privateKey);
        //设置请求格式，固定值json
        certAlipayRequest.setFormat("json");
        //设置字符集
        certAlipayRequest.setCharset("utf-8");
        //设置签名类型
        certAlipayRequest.setSignType("RSA2");
        //设置应用公钥证书路径
        certAlipayRequest.setCertPath(appCertPath);
        //设置支付宝公钥证书路径
        certAlipayRequest.setAlipayPublicCertPath(alipayCertPath);
        //设置支付宝根证书路径
        certAlipayRequest.setRootCertPath(alipayRootCertPath);
        //构造client
        AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);

        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody("金币");
        model.setSubject("金币支付");
        model.setOutTradeNo(outNum);
        model.setTimeoutExpress("30m");
        model.setTotalAmount("0.01");
        model.setProductCode("金币");
        request.setBizModel(model);

        model.setBody("物流APP金币购买");
        model.setSubject("物流APP金币");

        request.setNotifyUrl("");
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            System.out.println(response.getBody()); //就是orderString 可以直接给客户端请求，无需再做处理。
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取token接口
    public static String getToken() throws AppException {
        long time = System.currentTimeMillis();
        if (StringUtils.isBlank(wxToken) || time - tokenTime > 7100 * 1000) {
            lock.lock();
            try {
                if (StringUtils.isBlank(wxToken) || time - tokenTime > 7100 * 1000) {
                    String wxAns = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx910deb30bf41ba3a&secret=437a9758e6c8f52f49cca02b533f4fdb");
                    JSONObject jo = JSONObject.parseObject(wxAns);
                    if (StringUtils.isBlank(jo.getString("access_token"))) {
                        wxToken = jo.getString("access_token");
                        tokenTime = time;
                    } else {
                        throw new AppException("cey9999", "获取微信token失败");
                    }
                } else {
                    return wxToken;
                }
            } catch (Exception e) {
                throw new AppException("cey9999", "获取微信token失败");
            } finally {
                lock.unlock();
            }
        }

        return wxToken;
    }

    // 微信支付提现红包
    public static String postForWxWithdrawal(String withdrawalId, String userOpenId, Integer amount, String certFilePath) throws AppException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, KeyStoreException, KeyManagementException {
        String nonceStr = UUID.randomUUID().toString().replace("-", "");
        StringBuffer allParam = new StringBuffer();
        allParam.append("amount=").append(amount).append("&");
        allParam.append("check_name=NO_CHECK&");
        allParam.append("desc=金币提现&");
        allParam.append("mch_appid=" + wxAppId + "&");
        allParam.append("mchid=" + mch_id + "&");
        allParam.append("nonce_str=").append(nonceStr).append("&");
        allParam.append("openid=").append(userOpenId).append("&");
        allParam.append("partner_trade_no=").append(withdrawalId).append("&");
        allParam.append("key=b534811e05584cff8593237757dad7a2");
        log.info(allParam.toString());

        String sign = DigestUtils.md5Hex(allParam.toString()).toUpperCase();
        log.info(sign);

        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        sb.append("<mch_appid>" + wxAppId + "</mch_appid>");
        sb.append("<mchid>" + 1584805601 + "</mchid>");
        sb.append("<nonce_str>").append(nonceStr).append("</nonce_str>");
        // 提现流水号
        sb.append("<partner_trade_no>").append(withdrawalId).append("</partner_trade_no>");
        sb.append("<openid>").append(userOpenId).append("</openid>");
        // 是否校验姓名
        sb.append("<check_name>NO_CHECK</check_name>");
        // 如果校验就要输入姓名
        //sb.append("<re_user_name>张三</re_user_name>");
        // 提现金额
        sb.append("<amount>").append(amount).append("</amount>");
        // 描述
        sb.append("<desc>金币提现</desc>");

        sb.append("<sign>").append(sign).append("</sign>");
        sb.append("</xml>");

        log.info("参数为：" + sb.toString());

        StringBuffer message = new StringBuffer();

        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        //本地请求证书使用
        FileInputStream instream = new FileInputStream(new File(certFilePath));
        keyStore.load(instream, mch_id.toCharArray());
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, null, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
        httpost.addHeader("Connection", "keep-alive");
        httpost.addHeader("Accept", "*/*");
        httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        httpost.addHeader("Host", "api.mch.weixin.qq.com");
        httpost.addHeader("X-Requested-With", "XMLHttpRequest");
        httpost.addHeader("Cache-Control", "max-age=0");
        httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
        httpost.setEntity(new StringEntity(sb.toString(), "UTF-8"));
        //log.info("executing request" + httpost.getRequestLine());
        CloseableHttpResponse response = httpclient.execute(httpost);
        try {
            HttpEntity entity = response.getEntity();
            log.info("----------------------------------------");
            log.info(response.getStatusLine() + "");
            if (entity != null) {
                log.info("Response content length: " + entity.getContentLength());
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
                String text;
                while ((text = bufferedReader.readLine()) != null) {
                    message.append(text);
                }
            }
            EntityUtils.consume(entity);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            response.close();
        }
        log.info("微信支付返回信息：" + message.toString());
        return message.toString();
    }

    public static AlipayFundTransUniTransferResponse postForAlipayWithdrawal(String withdrawalId, String userOpenId, String userName, BigDecimal amount,
                                                                             String appCertPath, String alipayCertPath, String alipayRootCertPath) throws Exception {
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
        certAlipayRequest.setAppId(appId);
        certAlipayRequest.setPrivateKey(privateKey);
        certAlipayRequest.setFormat("json");
        certAlipayRequest.setCharset("UTF8");
        certAlipayRequest.setSignType("RSA2");

        certAlipayRequest.setCertPath(appCertPath);
        certAlipayRequest.setAlipayPublicCertPath(alipayCertPath);
        certAlipayRequest.setRootCertPath(alipayRootCertPath);
        DefaultAlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
        request.setBizContent("{" +
                "\"out_biz_no\":\"" + withdrawalId + "\"," +
                "\"trans_amount\":\"" + amount + "\"," +
                "\"product_code\":\"TRANS_ACCOUNT_NO_PWD\"," +
                "\"biz_scene\":\"DIRECT_TRANSFER\"," +
                "\"order_title\":\"金币提现\"," +
                "\"payee_info\":{" +
                "\"identity\":\"" + userOpenId + "\"," +
                "\"identity_type\":\"ALIPAY_USER_ID\"," +
                "\"name\":\"" + userName + "\"," +
                "    }," +
                "\"remark\":\"金币提现\"," +
                "\"business_params\":\"{\\\"payer_show_name\\\":\\\"湖南福泰物流有限公司\\\"}\"," +
                "  }");

        AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);

        log.info(JSON.toJSONString(response));
        if (response.isSuccess()) {
            log.info("调用成功");
        } else {
            log.warn("调用失败");
        }
        return response;
    }


    public static void main(String[] args) throws Exception {
        //postForWxWithdrawal("123456", "ohO4Gt7wVPxIT1A9GjFaMYMiZY1s", 1, "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\apiclient_cert.p12");
        //  postForAlipayWithdrawal("wdl110112", "2088122702773445", "吴启豪", new BigDecimal("1.01"), "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\appCertPublicKey_2021001154650303.crt", "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\alipayCertPublicKey_RSA2.crt", "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\alipayRootCert.crt");
        newPayInit("pay123", "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\appCertPublicKey_2021001154650303.crt", "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\alipayCertPublicKey_RSA2.crt", "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\alipayRootCert.crt");
    }
}
